home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / weapon.c < prev    next >
C/C++ Source or Header  |  1993-01-16  |  14KB  |  536 lines

  1. /*    SCCS Id: @(#)weapon.c    3.1    93/01/15    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  *    This module contains code for calculation of "to hit" and damage
  7.  *    bonuses for any given weapon used, as well as weapons selection
  8.  *    code for monsters.
  9.  */
  10. #include    "hack.h"
  11.  
  12. #ifdef OVLB
  13.  
  14. static const char NEARDATA kebabable[] = { S_XORN, S_DRAGON, S_NAGA, S_GIANT, 0 };
  15.  
  16. /*
  17.  *    hitval returns an integer representing the "to hit" bonuses
  18.  *    of "otmp" against the monster type "ptr".
  19.  */
  20. int
  21. hitval(otmp, ptr)
  22. struct    obj *otmp;
  23. struct    permonst *ptr;
  24. {
  25.     int    tmp = 0;
  26.  
  27.     if (otmp->oclass == WEAPON_CLASS ||
  28.         otmp->otyp == PICK_AXE || otmp->otyp == UNICORN_HORN)
  29.         tmp += otmp->spe;
  30.  
  31. /*    Put weapon specific "to hit" bonuses in below:        */
  32.     tmp += objects[otmp->otyp].oc_hitbon;
  33.  
  34. /*    Put weapon vs. monster type "to hit" bonuses in below:    */
  35.  
  36.     /* Blessed weapons used against undead or demons */
  37.     if(otmp->oclass == WEAPON_CLASS && otmp->blessed &&
  38.        (is_demon(ptr) || is_undead(ptr))) tmp += 2;
  39.  
  40.     if(otmp->otyp >= SPEAR && otmp->otyp <= JAVELIN &&
  41.        index(kebabable, ptr->mlet)) tmp += 2;
  42.  
  43.     /* Check specially named weapon "to hit" bonuses */
  44.     if (otmp->oartifact) tmp += spec_abon(otmp, ptr);
  45.     return tmp;
  46. }
  47.  
  48. /*
  49.  *    dmgval returns an integer representing the damage bonuses
  50.  *    of "otmp" against the monster type "ptr".
  51.  */
  52. int
  53. dmgval(otmp, ptr)
  54. struct    obj *otmp;
  55. struct    permonst *ptr;
  56. {
  57.     int    tmp = 0;
  58.  
  59.     if(otmp->otyp == CREAM_PIE)    return(0);
  60.  
  61.     if(ptr->msize >= MZ_HUMAN) {
  62.         if(objects[otmp->otyp].oc_wldam)
  63.         tmp = rnd(objects[otmp->otyp].oc_wldam);
  64.         switch (otmp->otyp) {
  65.         case CROSSBOW_BOLT:
  66.         case MORNING_STAR:
  67.         case PARTISAN:
  68.         case ELVEN_BROADSWORD:
  69.         case BROADSWORD:    tmp++; break;
  70.  
  71.         case FLAIL:
  72.         case RANSEUR:
  73.         case VOULGE:        tmp += rnd(4); break;
  74.  
  75.         case ACID_VENOM:
  76.         case HALBERD:
  77.         case SPETUM:        tmp += rnd(6); break;
  78.  
  79.         case BATTLE_AXE:
  80.         case BARDICHE:
  81.         case TRIDENT:        tmp += d(2,4); break;
  82.  
  83.         case TSURUGI:
  84.         case DWARVISH_MATTOCK:
  85.         case TWO_HANDED_SWORD:    tmp += d(2,6); break;
  86.         }
  87.     } else {
  88.         if(objects[otmp->otyp].oc_wsdam)
  89.         tmp = rnd(objects[otmp->otyp].oc_wsdam);
  90.         switch (otmp->otyp) {
  91.         case CROSSBOW_BOLT:
  92.         case MACE:
  93.         case WAR_HAMMER:
  94.         case FLAIL:
  95.         case SPETUM:
  96.         case TRIDENT:        tmp++; break;
  97.  
  98.         case BATTLE_AXE:
  99.         case BARDICHE:
  100.         case BILL_GUISARME:
  101.         case GUISARME:
  102.         case LUCERN_HAMMER:
  103.         case MORNING_STAR:
  104.         case RANSEUR:
  105.         case BROADSWORD:
  106.         case ELVEN_BROADSWORD:
  107.         case VOULGE:        tmp += rnd(4); break;
  108.  
  109.         case ACID_VENOM:    tmp += rnd(6); break;
  110.         }
  111.     }
  112.     if (otmp->oclass == WEAPON_CLASS || otmp->otyp == PICK_AXE
  113.                         || otmp->otyp == UNICORN_HORN)
  114.         tmp += otmp->spe;
  115.  
  116.     tmp -= otmp->oeroded;
  117.  
  118.     if (objects[otmp->otyp].oc_material <= LEATHER && thick_skinned(ptr))
  119.         /* thick skinned/scaled creatures don't feel it */
  120.         tmp = 0;
  121.     if (ptr == &mons[PM_SHADE] && objects[otmp->otyp].oc_material != SILVER)
  122.         tmp = 0;
  123.  
  124. /*    Put weapon vs. monster type damage bonuses in below:    */
  125.     if(otmp->oclass == WEAPON_CLASS) {
  126.         if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
  127.         tmp += rnd(4);
  128.         if ((otmp->otyp == AXE || otmp->otyp == BATTLE_AXE)
  129.         && is_wooden(ptr))
  130.         tmp += rnd(4);
  131.         if (objects[otmp->otyp].oc_material == SILVER && hates_silver(ptr))
  132.         tmp += rnd(20);
  133.     }
  134.  
  135.     return(tmp);
  136. }
  137.  
  138. void
  139. set_uasmon()        /* update the "uasmon" structure */
  140. {
  141. #ifdef POLYSELF
  142.     if(u.umonnum >= 0) uasmon = &mons[u.umonnum];
  143.     else {
  144. #endif
  145.  
  146.         uasmon = &playermon;
  147.         playermon.mlevel = u.ulevel;
  148.         playermon.ac = u.uac;
  149.         playermon.mr = (u.ulevel > 8) ? 5 * (u.ulevel-7) : u.ulevel;
  150. #ifdef POLYSELF
  151.     }
  152. #endif
  153.     return;
  154. }
  155.  
  156. #endif /* OVLB */
  157. #ifdef OVL0
  158.  
  159. #define    Oselect(x)    if((otmp = oselect(mtmp, x))) return(otmp);
  160.  
  161. static struct obj * FDECL(oselect, (struct monst *,int));
  162.  
  163. static struct obj *
  164. oselect(mtmp, x)
  165. struct monst *mtmp;
  166. int x;
  167. {
  168.     struct obj *otmp;
  169.  
  170.     for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) {
  171.         if (otmp->otyp == x && touch_artifact(otmp,mtmp))
  172.             return otmp;
  173.     }
  174.     return (struct obj *)0;
  175. }
  176.  
  177. static const int NEARDATA rwep[] =
  178.     { DWARVISH_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN,
  179.       SHURIKEN, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW,
  180.       CROSSBOW_BOLT, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, ROCK,
  181.       LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE
  182.       /* note: CREAM_PIE should NOT be #ifdef KOPS */
  183.       };
  184.  
  185. static struct obj *propellor;
  186.  
  187. struct obj *
  188. select_rwep(mtmp)    /* select a ranged weapon for the monster */
  189. register struct monst *mtmp;
  190. {
  191.     register struct obj *otmp;
  192.     int i;
  193.  
  194. #ifdef KOPS
  195.     char mlet = mtmp->data->mlet;
  196. #endif
  197.  
  198.     propellor = &zeroobj;
  199. #ifdef KOPS
  200.     if(mlet == S_KOP)    /* pies are first choice for Kops */
  201.         Oselect(CREAM_PIE);
  202. #endif
  203.     if(throws_rocks(mtmp->data))    /* ...boulders for giants */
  204.         Oselect(BOULDER);
  205.     /*
  206.      * other than these two specific cases, always select the
  207.      * most potent ranged weapon to hand.
  208.      */
  209.     for (i = 0; i < SIZE(rwep); i++) {
  210.         int prop;
  211.  
  212.         propellor = &zeroobj;
  213.         /* shooting gems from slings; this goes just before the darts */
  214.         if (rwep[i]==DART && !likes_gems(mtmp->data)
  215.             && (propellor = m_carrying(mtmp, SLING))) {
  216.         for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
  217.             if(otmp->oclass==GEM_CLASS &&
  218.                 (otmp->otyp != LOADSTONE || !otmp->cursed))
  219.             return(otmp);
  220.         }
  221.         }
  222.         prop = (objects[rwep[i]]).w_propellor;
  223.         if (prop > 0) {
  224.         switch (prop) {
  225.         case WP_BOW:
  226.           propellor = (oselect(mtmp, ELVEN_BOW));
  227.           if (!propellor) propellor = (oselect(mtmp, BOW));
  228.           if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW));
  229.           break;
  230.         case WP_SLING:
  231.           propellor = (oselect(mtmp, SLING));
  232.           break;
  233.         case WP_CROSSBOW:
  234.           propellor = (oselect(mtmp, CROSSBOW));
  235.         }
  236. #ifdef MUSE
  237.         if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor
  238.                 && mtmp->weapon_check == NO_WEAPON_WANTED)
  239.             propellor = 0;
  240. #endif
  241.         }
  242.         /* propellor = obj, propellor to use
  243.          * propellor = &zeroobj, doesn't need a propellor
  244.          * propellor = 0, needed one and didn't have one
  245.          */
  246.         if (propellor != 0) {
  247.         /* Note: cannot use m_carrying for loadstones, since it will
  248.          * always select the first object of a type, and maybe the
  249.          * monster is carrying two but only the first is unthrowable.
  250.          */
  251.         if (rwep[i] != LOADSTONE) {
  252. #ifdef MUSE
  253.             /* Don't throw a cursed weapon-in-hand */
  254.             if ((otmp = oselect(mtmp, rwep[i]))
  255.                 && (!otmp->cursed || otmp != MON_WEP(mtmp)))
  256.                 return(otmp);
  257. #else
  258.             Oselect(rwep[i]);
  259. #endif
  260.         } else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) {
  261.             if (otmp->otyp == LOADSTONE && !otmp->cursed)
  262.             return otmp;
  263.         }
  264.         }
  265.       }
  266.  
  267.     /* failure */
  268.     return (struct obj *)0;
  269. }
  270.  
  271. /* 0 = used by any monster; 1 = only used by strong monsters */
  272. static const struct hwep { short otyp, big; } NEARDATA hwep[] = {
  273.       {TSURUGI,1}, {RUNESWORD,0},
  274.       {DWARVISH_MATTOCK,1}, {TWO_HANDED_SWORD,1}, {BATTLE_AXE,1},
  275.       {KATANA,0}, {UNICORN_HORN,1}, {CRYSKNIFE,0},
  276.       {TRIDENT,0}, {LONG_SWORD,0}, {ELVEN_BROADSWORD,0}, {BROADSWORD,0},
  277.       {LUCERN_HAMMER,1}, {SCIMITAR,1}, {SILVER_SABER,0}, {HALBERD,1},
  278.       {PARTISAN,1}, {LANCE,1}, {FAUCHARD,1}, {BILL_GUISARME,1},
  279.       {BEC_DE_CORBIN,1}, {GUISARME,1}, {RANSEUR,1}, {SPETUM,1},
  280.       {VOULGE,1}, {BARDICHE,0}, {MORNING_STAR,0}, {GLAIVE,0},
  281.       {ELVEN_SHORT_SWORD,0}, {DWARVISH_SHORT_SWORD,0}, {SHORT_SWORD,0},
  282.       {ORCISH_SHORT_SWORD,0}, {MACE,0}, {AXE,0}, {DWARVISH_SPEAR,0},
  283.       {ELVEN_SPEAR,0}, {SPEAR,0}, {ORCISH_SPEAR,0}, {FLAIL,0},
  284.       {QUARTERSTAFF,1}, {JAVELIN,0}, {AKLYS,0}, {CLUB,0}, {PICK_AXE,0},
  285. #ifdef KOPS
  286.       {RUBBER_HOSE,0},
  287. #endif /* KOPS */
  288.       {WAR_HAMMER,0}, {ELVEN_DAGGER,0}, {DAGGER,0}, {ORCISH_DAGGER,0},
  289.       {ATHAME,0}, {SCALPEL,0}, {KNIFE,0}, {WORM_TOOTH,0}, {BULLWHIP,0}
  290.     };
  291.  
  292. struct obj *
  293. select_hwep(mtmp)    /* select a hand to hand weapon for the monster */
  294. register struct monst *mtmp;
  295. {
  296.     register struct obj *otmp;
  297.     register int i;
  298.     register const struct hwep *hw;
  299.     boolean strong = strongmonst(mtmp->data);
  300.  
  301.     if(is_giant(mtmp->data))    /* giants just love to use clubs */
  302.         Oselect(CLUB);
  303.  
  304.     /* only strong monsters can wield big (esp. long) weapons */
  305.     /* all monsters can wield the remaining weapons */
  306.     for (i = 0, hw = hwep; i < SIZE(hwep); i++, hw++)
  307.         if ((strong || !hw->big) &&
  308. #ifdef MUSE
  309.           (!objects[hw->otyp].oc_bimanual || !which_armor(mtmp, W_ARMS)) &&
  310. #endif
  311.     (objects[hw->otyp].oc_material != SILVER || !hates_silver(mtmp->data)))
  312.         Oselect(hw->otyp);
  313.  
  314.     /* failure */
  315.     return (struct obj *)0;
  316. }
  317.  
  318. #ifdef MUSE
  319. /* Called after polymorphing a monster, robbing it, etc....  Monsters
  320.  * otherwise never unwield stuff on their own.  Shouldn't print messages.
  321.  */
  322. void
  323. possibly_unwield(mon)
  324. register struct monst *mon;
  325. {
  326.     register struct obj *obj;
  327.     struct obj *otmp, *backobj, *mw_tmp;
  328.  
  329.     if (!(mw_tmp = MON_WEP(mon)))
  330.         return;
  331.     for(obj=mon->minvent; obj; obj=obj->nobj)
  332.         if (obj == mw_tmp) break;
  333.     if (!obj) { /* The weapon was stolen or destroyed */
  334.         MON_NOWEP(mon);
  335.         mon->weapon_check = NEED_WEAPON;
  336.         return;
  337.     }
  338.     if (!attacktype(mon->data, AT_WEAP)) {
  339.         MON_NOWEP(mon);
  340.         mon->weapon_check = NO_WEAPON_WANTED;
  341.         if (cansee(mon->mx, mon->my)) {
  342.             pline("%s drops %s.", Monnam(mon),
  343.                 distant_name(obj, doname));
  344.         }
  345.         backobj = 0;
  346.         for(otmp = mon->minvent; otmp; otmp = otmp->nobj) {
  347.             /* flooreffects unnecessary, can't wield boulders */
  348.             if (otmp == obj) {
  349.                 if (!backobj) mon->minvent = otmp->nobj;
  350.                 else backobj->nobj = otmp->nobj;
  351.                 place_object(otmp, mon->mx, mon->my);
  352.                 otmp->nobj = fobj;
  353.                 fobj = otmp;
  354.                 stackobj(fobj);
  355.                 if(cansee(mon->mx,mon->my))
  356.                     newsym(mon->mx, mon->my);
  357.                 break;
  358.             }
  359.             backobj = otmp;
  360.         }
  361.         return;
  362.     }
  363.     /* The remaining case where there is a change is where a monster
  364.      * is polymorphed into a stronger/weaker monster with a different
  365.      * choice of weapons.  This has no parallel for players.  It can
  366.      * be handled by waiting until mon_wield_item is actually called.
  367.      * Though the monster still wields the wrong weapon until then,
  368.      * this is OK since the player can't see it.
  369.      * Possible problem: big monster with big cursed weapon gets
  370.      * polymorphed into little monster.  But it's not quite clear how to
  371.      * handle this anyway....
  372.      */
  373.     mon->weapon_check = NEED_WEAPON;
  374.     return;
  375. }
  376.  
  377. /* Let a monster try to wield a weapon, based on mon->weapon_check.
  378.  * Returns 1 if the monster took time to do it, 0 if it did not.
  379.  */
  380. int
  381. mon_wield_item(mon)
  382. register struct monst *mon;
  383. {
  384.     struct obj *obj;
  385.  
  386.     /* This case actually should never happen */
  387.     if (mon->weapon_check == NO_WEAPON_WANTED) return 0;
  388.  
  389.     switch(mon->weapon_check) {
  390.         case NEED_HTH_WEAPON:
  391.             obj = select_hwep(mon);
  392.             break;
  393.         case NEED_RANGED_WEAPON:
  394.             (void)select_rwep(mon);
  395.             obj = propellor;
  396.             break;
  397.         case NEED_PICK_AXE:
  398.             obj = m_carrying(mon, PICK_AXE);
  399.             break;
  400.         default: impossible("weapon_check %d for %s?",
  401.                 mon->weapon_check, mon_nam(mon));
  402.             return 0;
  403.     }
  404.     if (obj && obj != &zeroobj) {
  405.         struct obj *mw_tmp = MON_WEP(mon);
  406.         if (mw_tmp == obj) { /* already wielding it */
  407.             mon->weapon_check = NEED_WEAPON;
  408.             return 0;
  409.         }
  410.         /* Actually, this isn't necessary--as soon as the monster
  411.          * wields the weapon, the weapon welds itself, so the monster
  412.          * can know it's cursed and needn't even bother trying.
  413.          * Still....
  414.          */
  415.         if (mw_tmp && mw_tmp->cursed) {
  416.             if (obj->otyp == PICK_AXE) {
  417.             if (canseemon(mon)) {
  418.                 pline("Since %s weapon %s welded to %s hand,",
  419.                 s_suffix(mon_nam(mon)),
  420.                 (mw_tmp->quan == 1L) ? "is" : "are",
  421.                 humanoid(mon->data)
  422.                     ? (mon->female ? "her" : "his")
  423.                     : "its");
  424.                 pline("%s cannot wield that %s.",
  425.                 mon_nam(mon), xname(obj));
  426.                 mw_tmp->bknown = 1;
  427.             }
  428.             } else {
  429.             if (canseemon(mon)) {
  430.                 pline("%s tries to wield %s.", Monnam(mon),
  431.                 doname(obj));
  432.                 pline("%s %s %s welded to %s hand!",
  433.                 s_suffix(Monnam(mon)), xname(mw_tmp),
  434.                 (mw_tmp->quan == 1L) ? "is" : "are",
  435.                 humanoid(mon->data)
  436.                     ? (mon->female ? "her" : "his")
  437.                     : "its");
  438.                 mw_tmp->bknown = 1;
  439.             }
  440.             }
  441.             mon->weapon_check = NO_WEAPON_WANTED;
  442.             return 1;
  443.         }
  444.         mon->mw = obj;        /* wield obj */
  445.         mon->weapon_check = NEED_WEAPON;
  446.         if (canseemon(mon)) {
  447.             pline("%s wields %s!", Monnam(mon), doname(obj));
  448.             if (obj->cursed) {
  449.                 pline("%s %s to %s hand!",
  450.                     The(xname(obj)),
  451.                     (obj->quan == 1L) ? "welds itself"
  452.                         : "weld themselves",
  453.                     s_suffix(mon_nam(mon)));
  454.                 obj->bknown = 1;
  455.             }
  456.         }
  457.         return 1;
  458.     }
  459.     mon->weapon_check = NEED_WEAPON;
  460.     return 0;
  461. }
  462.  
  463. /* rearrange a monster's inventory so that wielded weapon is first */
  464. void
  465. sort_mwep(mon)
  466. struct monst *mon;
  467. {
  468.     struct obj *otmp, *prev, *mw_tmp = MON_WEP(mon);
  469.  
  470.     if (!mw_tmp) return;
  471.     for (otmp = mon->minvent, prev = 0; otmp; otmp = otmp->nobj) {
  472.         if (otmp == mw_tmp)  break;
  473.         prev = otmp;
  474.     }
  475.     if (!otmp) {
  476.         MON_NOWEP(mon);
  477.     } else if (prev) {
  478.         prev->nobj = otmp->nobj;
  479.         otmp->nobj = mon->minvent;
  480.         mon->minvent = otmp;
  481.     }
  482. }
  483. #endif
  484.  
  485. int
  486. abon() {    /* attack bonus for strength & dexterity */
  487.     int    sbon;
  488.     register int    str = ACURR(A_STR), dex = ACURR(A_DEX);
  489.  
  490. #ifdef POLYSELF
  491.     if (u.umonnum >= 0) return(adj_lev(&mons[u.umonnum])-3);
  492. #endif
  493.     if (str < 6) sbon = -2;
  494.     else if (str < 8) sbon = -1;
  495.     else if (str < 17) sbon = 0;
  496.     else if (str < 69) sbon = 1;    /* up to 18/50 */
  497.     else if (str < 118) sbon = 2;
  498.     else sbon = 3;
  499. /*
  500.  *    Temporary kludge - make it a bit easier for a low level character
  501.  *               to hit until we tune the game a little better.
  502.  */
  503.     sbon += (u.ulevel < 3) ? 1 : 0;
  504.  
  505.     if (dex < 4) return(sbon-3);
  506.     else if (dex < 6) return(sbon-2);
  507.     else if (dex < 8) return(sbon-1);
  508.     else if (dex < 14) return(sbon);
  509.     else return(sbon + dex-14);
  510. }
  511.  
  512. #endif /* OVL0 */
  513. #ifdef OVL1
  514.  
  515. int
  516. dbon() {    /* damage bonus for strength */
  517.     register int    str = ACURR(A_STR);
  518.  
  519. #ifdef POLYSELF
  520.     if (u.umonnum >= 0) return(0);
  521. #endif
  522.  
  523.     if (str < 6) return(-1);
  524.     else if (str < 16) return(0);
  525.     else if (str < 18) return(1);
  526.     else if (str == 18) return(2);        /* up to 18 */
  527.     else if (str < 94) return(3);        /* up to 18/75 */
  528.     else if (str < 109) return(4);        /* up to 18/90 */
  529.     else if (str < 118) return(5);        /* up to 18/99 */
  530.     else return(6);
  531. }
  532.  
  533. #endif /* OVL1 */
  534.  
  535. /*weapon.c*/
  536.